﻿using System;
using System.Collections.Generic;
using System.Text;
using SdmxMl.Manager;

namespace SdmxMl.Common
{
    public class UrnParser
    {
        #region Private members


        private string _urn;

        #endregion

        #region Properties

        public bool IsSupported { get;  set; }
        public string Version { get; set; }
        public string AgencyId { get; set; }
        public string ArtefactId { get; set; }
        public SdmxMl.Manager.SdmxArtefactType ArType { get; set; }
        public string SubType { get; set; }
        public string SubTypeId { get; set; }
        public string SubmittedUrn { get; private set; }

        public ArtefactRefTyped TypedReference { get { return new ArtefactRefTyped(ArType, FullIdent); } }

        public string FullIdent
        {
            get
            {
                StringBuilder sb = new StringBuilder();
                sb.Append(AgencyId).Append('+');
                sb.Append(ArtefactId).Append('+');
                sb.Append(Version);
                return sb.ToString();
            }
        }

        #endregion

        public static string UrnSdmx_21_to_20(string urn21)
        {
            string urn20 = urn21.Replace('(', '[');
            urn20 = urn20.Replace(')', ']');
           // urn20 = urn20.Replace(".datastructure.", ".keyfamily.");

            return urn20;
        }

        public static string UrnSdmx_20_to_21(string urn20)
        {
            string urn21 = urn20.Replace('[', '(');
            urn21 = urn21.Replace(']', ')');
            urn21 = urn21.Replace(".keyfamily.", ".datastructure.");

            return urn21;
        }

        #region Constructor

        /// <summary>
        /// C'tor expects URN based on SDMX urn for Editor navigation
        /// </summary>
        /// <param name="urn"></param>
        public UrnParser(string urn)
        {
            SubmittedUrn = urn.Replace('(', '[');
            SubmittedUrn = SubmittedUrn.Replace(')', ']');
            SubTypeId = string.Empty;

            IsSupported = SubmittedUrn != null && urn.StartsWith(UrnManager.UrnBase);
            if (IsSupported)
            {
                _urn = SubmittedUrn.Substring(UrnManager.UrnBase.Length + 1);
                GetVersion();
                GetArtefactFullId();
            }
        }

        #endregion

        #region Private Methods

        private void GetVersion()
        {
            Version = "1.0"; // SDMX default
            int index = _urn.IndexOf('[');
            if (index > 0)
            {
                string braket = _urn.Substring(index);
                index = braket.IndexOf(']');
                if (index > 0)
                {
                    braket = braket.Substring(0, index+1);
                    _urn = _urn.Replace(braket, "");
                    Version = braket.Substring(1);
                    Version = Version.TrimEnd(']');
                }
                else
                    IsSupported = false;
            }
        }


        private void GetArtefactFullId()
        {
            if (IsSupported)
            {
                try
                {
                    int index = _urn.IndexOf("=");
                    if (index > 0)
                    {
                        string sType = _urn.Substring(0, index);
                        string valId = _urn.Substring(index + 1);

                        // Artefact Type
                        ArType = GetUrnArtefactType(sType);
                        // Correct error for old urn isong hierarchicalcodelist instead of codelist for hierarchicalcodelist
                        if (ArType == SdmxArtefactType.None && sType.StartsWith("hierarchicalcodelist"))
                            ArType = SdmxArtefactType.HierarchicalCodelists;
                        IsSupported = ArType != SdmxArtefactType.None;

                        //Now ID, AgencyId and eventually subId
                        string[] arr = valId.Split(':');
                        AgencyId = arr[0];
                        index = arr[1].IndexOf('.');
                        if (index > 0)
                        {
                            SubTypeId = arr[1].Substring(index + 1);
                            ArtefactId = arr[1].Substring(0, index);
                        }
                        else
                        {
                            SubTypeId = string.Empty;
                            ArtefactId = arr[1];
                        }
                    }
                    else
                        IsSupported = false;

                }
                catch
                {
                    IsSupported = false;
                }
            }
            
        }

        /// <summary> Retrieves artefact type described in sdmx URN as well as optional inner artefact element</summary>
        /// <param name="urnPart">Urn parg bsfore artefact full ID. So before symbol = </param>
        /// <returns>Type of artefact</returns>
        private SdmxArtefactType GetUrnArtefactType(string urnPart)
        {
            SdmxArtefactType arType = SdmxArtefactType.None;
            for (int i = 1; i < UrnManager._arrUrnSdmxPackage.Length; i++)
            {
                if (urnPart.StartsWith(UrnManager._arrUrnSdmxPackage[i]))
                {
                    arType = (SdmxArtefactType)i;
                    if (urnPart.Length > UrnManager._arrUrnSdmxPackage[i].Length + 1)
                    {
                        // Caution, two type are with same string, so correct type according to refered sub type
                        SubType = urnPart.Substring(UrnManager._arrUrnSdmxPackage[i].Length + 1);
                        if (SubType == "ReportStructure" || SubType == "MetadataStructureDefinition")
                            arType = SdmxArtefactType.MetadataStructureDefinitions;
                        else if (SubType == "HierarchicalCodelist" || SubType == "Hierarchy" || SubType == "CodelistRef")
                            arType = SdmxArtefactType.HierarchicalCodelists;

                        // if subtype equivalent to artefact, ignore subtype information
                        for (int a = 1; a < UrnManager._arrUrnArtefact.Length; ++a )
                        {
                            if (SubType == UrnManager._arrUrnArtefact[i].Substring(1))
                            {
                                SubType = string.Empty;
                                break;
                            }
                        }
                    }
                    break;
                }
            }
            return arType;
        }


        #endregion

    }
}
